package com.wjh.anyview.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.wjh.anyview.auth.util.SecurityUtil;
import com.wjh.anyview.dao.*;
import com.wjh.anyview.entity.bo.examServiceBo.*;
import com.wjh.anyview.entity.dto.CommonResult;
import com.wjh.anyview.entity.po.*;
import com.wjh.anyview.entity.vo.examControllerVo.ExamTeacherVo;
import com.wjh.anyview.entity.vo.examControllerVo.ExamVo;
import com.wjh.anyview.service.ExamService;
import com.wjh.anyview.service.constant.ExamStatusConstant;
import com.wjh.anyview.service.constant.MitConstant;
import com.wjh.anyview.service.constant.StringConstant;
import com.wjh.anyview.util.TimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wjh
 * @date 2021/10/12 13:36
 * @Package com.wjh.anyview.service.impl
 */
@Service
@Slf4j
public class ExamServiceImpl implements ExamService {
    @Resource
    private ClazzCourseMapper clazzCourseMapper;

    @Resource
    private ExamCourseMapper examCourseMapper;

    @Resource
    private ExamMapper examMapper;

    @Resource
    private BankQuestionMapper bankQuestionMapper;

    @Resource
    private StudentQuestionMapper studentQuestionMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private AnswerMapper answerMapper;

    @Resource
    private QuestionMapper questionMapper;

    @Override
    public CommonResult<List<ExamVo>> listExamByClazzId(Long clazzId) {
        QueryWrapper<ClazzCourse> clazzCourseQueryWrapper = new QueryWrapper<>();
        clazzCourseQueryWrapper.eq("clazz_id", clazzId);
        //根据clazz_id找到 ClazzCourse
        List<ClazzCourse> clazzCourseList = clazzCourseMapper.selectList(clazzCourseQueryWrapper);
        List<ExamVo> examVoList = new ArrayList<>();
        //根据课程id查询中间po类 ExamCourse
        clazzCourseList.forEach(clazzCourse -> {
            QueryWrapper<ExamCourse> examCourseQueryWrapper = new QueryWrapper<>();
            examCourseQueryWrapper.eq("course_id", clazzCourse.getCourseId());
            ExamCourse examCourse = examCourseMapper.selectOne(examCourseQueryWrapper);

            if (examCourse != null) {
                //根据考试id查询Exam对象
                Exam exam = examMapper.selectById(examCourse.getExamId());
                ExamVo examVo = new ExamVo();
                examVo.setExamId(exam.getId());
                examVo.setExamName(exam.getExamName());
                examVo.setStatus(exam.getStatus());
                examVo.setStartTime(TimeUtil.timestampToDate(exam.getStartTime()));
                examVo.setEndTime(TimeUtil.timestampToDate(exam.getEndTime()));
                examVo.setLocation(exam.getLocation());
                examVo.setBankId(exam.getBankId());
                if (Objects.equals(exam.getStatus(), ExamStatusConstant.NO_START)) {
                    examVo.setStatusName("未开始");
                }
                if (Objects.equals(exam.getStatus(), ExamStatusConstant.PER_START)) {
                    examVo.setStatusName("准备中");
                }
                if (Objects.equals(exam.getStatus(), ExamStatusConstant.IN_PROGRESS)) {
                    examVo.setStatusName("进行中");
                }
                if (Objects.equals(exam.getStatus(), ExamStatusConstant.END)) {
                    examVo.setStatusName("已结束");
                }
                examVoList.add(examVo);
            }

        });
        //过滤掉已经结束的考试
        List<ExamVo> collect = examVoList.stream().filter(examVo -> examVo.getStatus() <= 3).collect(Collectors.toList());
        return CommonResult.operateSuccess(collect);
    }

    @Override
    @Transactional
    public CommonResult<?> finish(FinishBo finishBo) {
        //判断是否已经提交过了答案
        QueryWrapper<StudentQuestion> wrapper0 = new QueryWrapper<StudentQuestion>()
                .eq("student_id", SecurityUtil.getUserId())
                .eq("exam_id", finishBo.getExamId());
        List<StudentQuestion> list = studentQuestionMapper.selectList(wrapper0);
        //如果提交过答案就更新新提交的答案
        if (list.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
                StudentQuestion studentQuestion = list.get(i);
                studentQuestion.setAnswer(finishBo.getAnswerList().get(i));
                studentQuestionMapper.updateById(studentQuestion);
            }
            return CommonResult.operateSuccess();
        }

        //根据examId查询bankId
        Exam exam = examMapper.selectById(finishBo.getExamId());

        List<String> answerList = finishBo.getAnswerList();
        QueryWrapper<BankQuestion> wrapper = new QueryWrapper<>();
        wrapper.eq("bank_id", exam.getBankId());
        List<BankQuestion> bankQuestionList = bankQuestionMapper.selectList(wrapper);
        for (int i = 0; i < answerList.size(); i++) {
            StudentQuestion studentQuestion = new StudentQuestion();
            //答题学生
            studentQuestion.setStudentId(SecurityUtil.getUserId());
            //题目id
            studentQuestion.setQuestionId(bankQuestionList.get(i).getQuestionId());
            //答案
            studentQuestion.setAnswer(answerList.get(i));
            //考试id
            studentQuestion.setExamId(finishBo.getExamId());
            //插入数据库
            studentQuestionMapper.insert(studentQuestion);
        }
        return CommonResult.operateSuccess();
    }

    @Override
    @Transactional
    public CommonResult<?> arrangeExamByCourseId(ArrangeExamBo arrangeExamBo) {
        //查重，查看该课程是否已经有考试了
        QueryWrapper<ExamCourse> examCourseQueryWrapper = new QueryWrapper<>();
        examCourseQueryWrapper.eq("course_id", arrangeExamBo.getCourseId());
        ExamCourse examCourseSelect = examCourseMapper.selectOne(examCourseQueryWrapper);
        if (examCourseSelect != null) {
            return CommonResult.operateFailWithMessage("该课程已经安排考试了，无法再安排考试!");
        }
        //考试时间必须提前一天及以上安排
        Date startDate = TimeUtil.stringToDate(arrangeExamBo.getStartTime());
        //传入日期不合法
        if (startDate == null) {
            return CommonResult.operateFailWithMessage(StringConstant.DATA_ILLEGAL);
        }
        //比较时间安排是否合理
        if (Long.parseLong(TimeUtil.addMitToTimeStamp(new Date(), 24 * 60)) > TimeUtil.dateToTimestamp(startDate)) {
            return CommonResult.operateFailWithMessage("考试时间必须提前一天安排！");
        }
        //判断时间是否冲突的对象
        TimeConflictBo timeConflictBo = new TimeConflictBo();
        timeConflictBo.setCourseId(arrangeExamBo.getCourseId());
        //考试开始前2小时
        timeConflictBo.setMinTime(Long.valueOf(TimeUtil.minusMitToTimeStamp(startDate, 60 * 2)));
        //考试结束后的2小时
        timeConflictBo.setMaxTime(Long.parseLong(TimeUtil.addMitToTimeStamp(startDate, arrangeExamBo.getDuration())) + 3600 * 60 * 2);
        //考试时间有冲突
        if (judgeTimeConflict(timeConflictBo)) {
            return CommonResult.operateFailWithMessage("这些班级中某些班级的考试时间和你安排的考试时间有冲突，请重新安排！");
        }
        //封装前端传递过来的数据
        Exam exam = new Exam();
        exam.setExamName(arrangeExamBo.getExamName());
        exam.setInvigilatorId(arrangeExamBo.getInvigilatorId());
        exam.setStartTime(TimeUtil.dateToTimestamp(startDate));
        exam.setEndTime(Long.valueOf(TimeUtil.addMitToTimeStamp(startDate, arrangeExamBo.getDuration())));
        exam.setBankId(arrangeExamBo.getBankId());
        exam.setDuration(arrangeExamBo.getDuration());
        exam.setStatus((byte) 0);
        exam.setLocation("线上考试");
        //把exam对象插入数据库并获取id
        examMapper.saveExam(exam);
        ExamCourse examCourse = new ExamCourse();
        examCourse.setCourseId(arrangeExamBo.getCourseId());
        examCourse.setExamId(exam.getId());
        //插入course-exam关系
        examCourseMapper.insert(examCourse);
        return CommonResult.operateSuccess();
    }

    @Override
    public boolean judgeTimeConflict(TimeConflictBo timeConflictBo) {
        log.info("被判断的对象：" + timeConflictBo);
        Long min = timeConflictBo.getMinTime();
        Long max = timeConflictBo.getMaxTime();
        QueryWrapper<ClazzCourse> clazzCourseQueryWrapper = new QueryWrapper<>();
        clazzCourseQueryWrapper.eq("course_id", timeConflictBo.getCourseId());
        List<ClazzCourse> clazzCourseList = clazzCourseMapper.selectList(clazzCourseQueryWrapper);

        //需要判断时间是否冲突的班级id的集合
        List<Long> clazzIds = new ArrayList<>();
        clazzCourseList.forEach(clazzCourse -> clazzIds.add(clazzCourse.getClazzId()));
        log.info("相关班级对象的id（主键）：" + clazzIds);
        //根据班级id查询ClazzCourse对象
        List<ClazzCourse> clazzCourses = new ArrayList<>();
        clazzIds.forEach(clazzId -> {
            QueryWrapper<ClazzCourse> wrapper = new QueryWrapper<>();
            wrapper.eq("clazz_id", clazzId);
            List<ClazzCourse> list = clazzCourseMapper.selectList(wrapper);
            clazzCourses.addAll(list);
        });
        log.info("通过clazz_course表的clazzId字段查询出来的对应的clazzCourse对象：" + clazzCourses);
        //需要判断的所有课程id的集合
        List<Long> courseIdList = new ArrayList<>();
        clazzCourses.forEach(clazzCourse -> courseIdList.add(clazzCourse.getCourseId()));
        List<Long> collectCourseIdList = courseIdList.stream().distinct().collect(Collectors.toList());
        log.info("需要判断时间冲突的课程id集合（已去重）collectCourseIdList：" + collectCourseIdList);
        //根据courseId查询examId,examIdList是最终需要判断冲突考试的id集合
        List<Long> examIdList = new ArrayList<>();
        collectCourseIdList.forEach(courseId -> {
            QueryWrapper<ExamCourse> wrapper = new QueryWrapper<>();
            wrapper.eq("course_id", courseId);
            ExamCourse examCourse = examCourseMapper.selectOne(wrapper);
            if (examCourse != null) {
                examIdList.add(examCourse.getExamId());
            }
        });
        //根据examId查询时间
        List<Exam> examList = examMapper.selectBatchIds(examIdList);
        List<Long> startList = new ArrayList<>();
        List<Long> endList = new ArrayList<>();
        examList.forEach(exam -> {
            startList.add(exam.getStartTime());
            endList.add(exam.getEndTime());
        });
        return Collections.max(endList) >= min && Collections.min(startList) <= max;
    }

    @Override
    public CommonResult<ExamVo> getExamByCourseId(Long courseId) {
        QueryWrapper<ExamCourse> wrapper = new QueryWrapper<>();
        wrapper.eq("course_id", courseId);
        ExamCourse examCourse = examCourseMapper.selectOne(wrapper);
        if (examCourse == null) {
            return CommonResult.operateFailWithMessage("该课程没有安排考试！");
        }
        Exam exam = examMapper.selectById(examCourse.getExamId());
        ExamVo examVo = new ExamVo();
        examVo.setExamId(exam.getId());
        examVo.setExamName(exam.getExamName());
        examVo.setLocation(exam.getLocation());
        examVo.setStatus(exam.getStatus());
        examVo.setStartTime(TimeUtil.timestampToDate(exam.getStartTime()));
        examVo.setEndTime(TimeUtil.timestampToDate(exam.getEndTime()));
        if (Objects.equals(exam.getStatus(), ExamStatusConstant.NO_START)) {
            examVo.setStatusName("未开始");
        }
        if (Objects.equals(exam.getStatus(), ExamStatusConstant.PER_START)) {
            examVo.setStatusName("准备中");
        }
        if (Objects.equals(exam.getStatus(), ExamStatusConstant.IN_PROGRESS)) {
            examVo.setStatusName("进行中");
        }
        if (Objects.equals(exam.getStatus(), ExamStatusConstant.END)) {
            examVo.setStatusName("已结束");
        }
        return CommonResult.operateSuccess(examVo);
    }

    @Override
    public CommonResult<List<ExamTeacherVo>> listExamByInvigilatorId(Long invigilatorId) {
        QueryWrapper<Exam> wrapper = new QueryWrapper<>();
        wrapper.eq("invigilator_id", invigilatorId);
//        wrapper.le("status", ExamStatusConstant.IN_PROGRESS);
        List<Exam> examList = examMapper.selectList(wrapper);
        if (examList.size() == 0) {
            return CommonResult.operateFailWithMessage("您没有需要监考的考试！");
        }
        List<ExamTeacherVo> list = new ArrayList<>();
        examList.forEach(exam -> {
            ExamTeacherVo examTeacherVo = new ExamTeacherVo();
            examTeacherVo.setExamId(exam.getId());
            examTeacherVo.setExamName(exam.getExamName());
            examTeacherVo.setDuration(exam.getDuration());
            examTeacherVo.setStatus(exam.getStatus());
            if (Objects.equals(exam.getStatus(), ExamStatusConstant.NO_START)) {
                examTeacherVo.setStatusName("未开始");
            }
            if (Objects.equals(exam.getStatus(), ExamStatusConstant.PER_START)) {
                examTeacherVo.setStatusName("准备中");
            }
            if (Objects.equals(exam.getStatus(), ExamStatusConstant.IN_PROGRESS)) {
                examTeacherVo.setStatusName("进行中");
            }
            if (Objects.equals(exam.getStatus(), ExamStatusConstant.END)) {
                examTeacherVo.setStatusName("已结束");
            }
            examTeacherVo.setStartTime(TimeUtil.timestampToDate(exam.getStartTime()));
            list.add(examTeacherVo);
        });
        return CommonResult.operateSuccess(list);
    }

    @Override
    @Transactional
    public CommonResult<List<String>> beginExam(BeginExamBo beginExamBo) {
        Exam exam = examMapper.selectById(beginExamBo.getExamId());
        //不能大于20min外开始
        if (TimeUtil.timestampAddMit(System.currentTimeMillis(), MitConstant.MIT_20) < exam.getStartTime()) {
            return CommonResult.operateFailWithMessage("考试不允许大于20min提前开始！");
        }
        //准备时间不合理,为了方便测试，暂时最小1分钟
        if (beginExamBo.getPerTime() > MitConstant.MIT_20 || beginExamBo.getPerTime() < MitConstant.MIT_1) {
            return CommonResult.operateFailWithMessage("考试的准备时间太长或太短！");
        }
        //跟新考试状态和实际开始时间
        Exam newExam = new Exam();
        newExam.setId(exam.getId());
        //状态跟新为准备开始
        newExam.setStatus(ExamStatusConstant.PER_START);
        //跟新实际开始考试时间
        Long startTime = TimeUtil.timestampAddMit(System.currentTimeMillis(), beginExamBo.getPerTime());
        newExam.setStartTime(startTime);
        //更新实际结束考试时间
        Long endTime = TimeUtil.timestampAddMit(System.currentTimeMillis(), beginExamBo.getPerTime() + exam.getDuration());
        newExam.setEndTime(endTime);
        examMapper.updateById(newExam);
        List<String> numList = listNumByExamId(beginExamBo.getExamId());
        if (numList == null) {
            return CommonResult.operateFailWithMessage("examId不合法");
        }
        //返回学号合集
        return CommonResult.operateSuccess(numList);
    }

    @Override
    public List<String> listNumByExamId(Long examId) {
        //根据examId查询靠这门试的课程
        QueryWrapper<ExamCourse> wrapper = new QueryWrapper<>();
        wrapper.eq("exam_id", examId);
        List<ExamCourse> examCourseList = examCourseMapper.selectList(wrapper);
        if (examCourseList.size() == 0) {
            return null;
        }
        //根据课程id查找考这门试的班级,然后查询这个班级的所有学生
        List<String> numList = new ArrayList<>();
        examCourseList.forEach(examCourse -> {
            QueryWrapper<ClazzCourse> clazzCourseQueryWrapper = new QueryWrapper<>();
            clazzCourseQueryWrapper.eq("course_id", examCourse.getCourseId());
            Map<String, Object> columnMap = new HashMap<>(1);

            List<ClazzCourse> clazzCourseList = clazzCourseMapper.selectList(clazzCourseQueryWrapper);
            clazzCourseList.forEach(clazzCourse -> {
                columnMap.put("clazz_id", clazzCourse.getClazzId());
                List<User> users = userMapper.selectByMap(columnMap);
                users.forEach(user -> numList.add(user.getNum()));
            });

//            columnMap.put("clazz_id", clazzCourseMapper.selectOne(clazzCourseQueryWrapper).getClazzId());
//            List<User> users = userMapper.selectByMap(columnMap);
//            users.forEach(user -> numList.add(user.getNum()));
        });
        return numList;
    }

    @Override
    @Transactional
    public CommonResult<?> submitAnswer(SubmitAnswerBo submitAnswerBo) {
        //answer对象集合
        int num = 0;
        for (int i = 0; i < submitAnswerBo.getQuestionIdList().size(); i++) {
            Answer answer = new Answer();
            answer.setStudentId(SecurityUtil.getUserId());
            answer.setExamId(submitAnswerBo.getExamId());
            answer.setQuestionId(submitAnswerBo.getQuestionIdList().get(i));
            answer.setStudentAnswer(submitAnswerBo.getStudentAnswerList().get(i));
            //插入数据库保存
            num = num + answerMapper.insert(answer);
        }
        if (num > 0) {
            return CommonResult.operateSuccess();
        }
        log.warn("参数类型错误：" + submitAnswerBo);
        return CommonResult.operateFailWithMessage(StringConstant.SYSTEM_BUSY);
    }

    @Override
    public CommonResult<List<String>> queryAnswer(QueryAnswerBo queryAnswerBo) {
        QueryWrapper<StudentQuestion> wrapper = new QueryWrapper<StudentQuestion>()
                .eq("exam_id", queryAnswerBo.getExamId())
                .eq("student_id", queryAnswerBo.getStudentId());
        List<StudentQuestion> list = studentQuestionMapper.selectList(wrapper);
        List<String> answerList = new ArrayList<>();
        if (list.size() > 0) {
            list.forEach(u -> answerList.add(u.getAnswer()));
            return CommonResult.operateSuccess(answerList);
        } else {
            return CommonResult.operateFailWithMessage("该考生未提交答案!");
        }
    }

    @Override
    public CommonResult<List<Question>> listStudentAnswerByNumAndExamId(NumAndExamIdBo numAndExamIdBo) {
        QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .eq("num", numAndExamIdBo.getNum());
        Long studentId = userMapper.selectOne(wrapper).getId();
        log.info("学生id：" + studentId);
        QueryWrapper<StudentQuestion> wrapper2 = new QueryWrapper<StudentQuestion>()
                .eq("student_id", studentId)
                .eq("exam_id", numAndExamIdBo.getExamId());
        List<StudentQuestion> list = studentQuestionMapper.selectList(wrapper2);
        List<Question> questionList = new ArrayList<>();
        list.forEach(studentQuestion -> {
            Question question = new Question();
            question.setAnswer(studentQuestion.getAnswer());

            Question questionForDb = questionMapper.selectById(studentQuestion.getQuestionId());
            question.setQuestion(questionForDb.getQuestion());
            question.setId(studentQuestion.getId());

            questionList.add(question);
        });
        if (questionList.size() > 0) {
            return CommonResult.operateSuccess(questionList);
        }
        return CommonResult.operateFailWithMessage("该考生未提交答案，无需评分!");
    }

    @Override
    public CommonResult<?> mark(MarkBo markBo) {
        StudentQuestion studentQuestion = new StudentQuestion();
        studentQuestion.setId(markBo.getStudentQuestionId());
        studentQuestion.setMark(markBo.getMark());
        if (studentQuestionMapper.updateById(studentQuestion) > 0) {
            return CommonResult.operateSuccess();
        }
        return CommonResult.operateFailWithMessage(StringConstant.SYSTEM_BUSY);
    }

}
